将结构写入文件的最佳方法是什么?
What is the best way to write a struct to file?
我有这两个结构:
struct pcap_hdr_s {
UInt32 magic_number;
UInt16 version_major;
UInt16 version_minor;
int32_t thiszone;
UInt32 sigfigs;
UInt32 snaplen;
UInt32 network;
};
//packet header
struct pcaprec_hdr_s {
UInt32 ts_sec;
UInt32 ts_usec;
UInt32 incl_len;
UInt32 orig_len;
};
初始化如下(举例):
let pcapHeader : pcap_hdr_s = pcap_hdr_s(magic_number: 0xa1b2c3d4,
version_major: 2,
version_minor: 4,
thiszone: 0,
sigfigs: 0,
snaplen:
pcap_record_size,
network: LINKTYPE_ETHERNET)
let pcapRecHeader : pcaprec_hdr_s = pcaprec_hdr_s(ts_sec: UInt32(ts.tv_sec),
ts_usec: UInt32(ts.tv_nsec),
incl_len: plen,
orig_len: length)
我尝试创建 Data/NSData 结构对象,如下所示:
//write pcap header
let pcapHeaderData : NSData = NSData(bytes: pcapHeader, length: sizeofValue(pcapHeader))
//write pcaprec header
let pcapRecHeaderData : NSData = NSData(bytes: pcapRecHeader, length: sizeofValue(pcapRecHeader))
但是每一行我总是得到这个错误:
"Connot convert value if type 'pcap_hdr_s' to expected arguemnt type 'UsafeRawPointer?'"
我查看了 Swift 中 UnsafeRawPointers 的文档,但我目前还没有充分了解如何从结构创建 NSData 对象。
我的方法是正确的还是有更好的方法来实现我的意图?
如果此数据初始化可行,我的下一步将是
- 将 pcapRecHeaderData 附加到 pcapHeaderData
- 使用 Data/NSData
提供的函数自动将 pcapHeaderData 写入 file/url
编辑:
//packet ethernet header
struct ethernet_hdr_s {
let dhost : [UInt8]
let shost : [UInt8]
let type : UInt16
};
let src_mac : [UInt8] = [0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB]
let dest_mac : [UInt8] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55]
let ethernetHeader : ethernet_hdr_s = ethernet_hdr_s(dhost: dest_mac, shost: src_mac, type: 0x0800)
编辑 2:
let payloadSize = packet.payload.count
let plen = (payloadSize < Int(pcap_record_size) ? payloadSize : Int(pcap_record_size));
bytesWritten = withUnsafePointer(to: &(packet.payload)) {
[=15=].withMemoryRebound(to: UInt8.self, capacity: Int(plen)) {
ostream.write([=15=], maxLength: Int(plen))
}
}
if bytesWritten != (Int(plen)) {
// Could not write all bytes, report error ...
NSLog("error in Writting packet payload, not all Bytes written: bytesWritten: %d|plen: %d", bytesWritten, Int(plen))
}
您可以在 Swift 3 中将 pcap_hdr_s
转换为 Data
,反之亦然
pcap_hdr_s
-> Data
var pcapHeader : pcap_hdr_s = pcap_hdr_s(magic_number ...
let data = withUnsafePointer(to: &pcapHeader) {
Data(bytes: UnsafePointer([=10=]), count: MemoryLayout.size(ofValue: pcapHeader))
}
Data
-> pcap_hdr_s
let header: pcap_hdr_s = data.withUnsafeBytes { [=11=].pointee }
您可以将任意数据写入 InputStream
而无需创建
(NS)Data
首先是对象。 "challenge" 是如何将指针转换为
write
方法预期的指向 UInt8
指针的结构:
let ostream = OutputStream(url: url, append: false)! // Add error checking here!
ostream.open()
var pcapHeader = pcap_hdr_s(...)
let headerSize = MemoryLayout.size(ofValue: pcapHeader)
let bytesWritten = withUnsafePointer(to: &pcapHeader) {
[=10=].withMemoryRebound(to: UInt8.self, capacity: headerSize) {
ostream.write([=10=], maxLength: headerSize)
}
}
if bytesWritten != headerSize {
// Could not write all bytes, report error ...
}
以同样的方式,您可以从 InputStream
:
中读取数据
let istream = InputStream(url: url)! // Add error checking here!
istream.open()
let bytesRead = withUnsafeMutablePointer(to: &pcapHeader) {
[=11=].withMemoryRebound(to: UInt8.self, capacity: headerSize) {
istream.read([=11=], maxLength: headerSize)
}
}
if bytesRead != headerSize {
// Could not read all bytes, report error ...
}
如果文件可能是在不同的平台上创建的
不同的字节顺序然后你可以检查 "magic" 和交换字节
如有必要(如 https://wiki.wireshark.org/Development/LibpcapFileFormat 所述):
switch pcapHeader.magic_number {
case 0xa1b2c3d4:
break // Already in host byte order
case 0xd4c3b2a1:
pcapHeader.version_major = pcapHeader.version_major.byteSwapped
pcapHeader.version_minor = pcapHeader.version_minor.byteSwapped
// ...
default:
// Unknown magic, report error ...
}
为了简化编写和读取结构的任务,可以定义
自定义扩展方法,例如
extension OutputStream {
enum ValueWriteError: Error {
case incompleteWrite
case unknownError
}
func write<T>(value: T) throws {
var value = value
let size = MemoryLayout.size(ofValue: value)
let bytesWritten = withUnsafePointer(to: &value) {
[=13=].withMemoryRebound(to: UInt8.self, capacity: size) {
write([=13=], maxLength: size)
}
}
if bytesWritten == -1 {
throw streamError ?? ValueWriteError.unknownError
} else if bytesWritten != size {
throw ValueWriteError.incompleteWrite
}
}
}
extension InputStream {
enum ValueReadError: Error {
case incompleteRead
case unknownError
}
func read<T>(value: inout T) throws {
let size = MemoryLayout.size(ofValue: value)
let bytesRead = withUnsafeMutablePointer(to: &value) {
[=13=].withMemoryRebound(to: UInt8.self, capacity: size) {
read([=13=], maxLength: size)
}
}
if bytesRead == -1 {
throw streamError ?? ValueReadError.unknownError
} else if bytesRead != size {
throw ValueReadError.incompleteRead
}
}
}
现在您可以使用
简单地书写和阅读
try ostream.write(value: pcapHeader)
try istream.read(value: &pcapHeader)
当然这只适用于像你这样的 "self-contained" 结构
pcap_hdr_s
和 pcaprec_hdr_s
.
我有这两个结构:
struct pcap_hdr_s {
UInt32 magic_number;
UInt16 version_major;
UInt16 version_minor;
int32_t thiszone;
UInt32 sigfigs;
UInt32 snaplen;
UInt32 network;
};
//packet header
struct pcaprec_hdr_s {
UInt32 ts_sec;
UInt32 ts_usec;
UInt32 incl_len;
UInt32 orig_len;
};
初始化如下(举例):
let pcapHeader : pcap_hdr_s = pcap_hdr_s(magic_number: 0xa1b2c3d4,
version_major: 2,
version_minor: 4,
thiszone: 0,
sigfigs: 0,
snaplen:
pcap_record_size,
network: LINKTYPE_ETHERNET)
let pcapRecHeader : pcaprec_hdr_s = pcaprec_hdr_s(ts_sec: UInt32(ts.tv_sec),
ts_usec: UInt32(ts.tv_nsec),
incl_len: plen,
orig_len: length)
我尝试创建 Data/NSData 结构对象,如下所示:
//write pcap header
let pcapHeaderData : NSData = NSData(bytes: pcapHeader, length: sizeofValue(pcapHeader))
//write pcaprec header
let pcapRecHeaderData : NSData = NSData(bytes: pcapRecHeader, length: sizeofValue(pcapRecHeader))
但是每一行我总是得到这个错误:
"Connot convert value if type 'pcap_hdr_s' to expected arguemnt type 'UsafeRawPointer?'"
我查看了 Swift 中 UnsafeRawPointers 的文档,但我目前还没有充分了解如何从结构创建 NSData 对象。 我的方法是正确的还是有更好的方法来实现我的意图?
如果此数据初始化可行,我的下一步将是
- 将 pcapRecHeaderData 附加到 pcapHeaderData
- 使用 Data/NSData 提供的函数自动将 pcapHeaderData 写入 file/url
编辑:
//packet ethernet header
struct ethernet_hdr_s {
let dhost : [UInt8]
let shost : [UInt8]
let type : UInt16
};
let src_mac : [UInt8] = [0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB]
let dest_mac : [UInt8] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55]
let ethernetHeader : ethernet_hdr_s = ethernet_hdr_s(dhost: dest_mac, shost: src_mac, type: 0x0800)
编辑 2:
let payloadSize = packet.payload.count
let plen = (payloadSize < Int(pcap_record_size) ? payloadSize : Int(pcap_record_size));
bytesWritten = withUnsafePointer(to: &(packet.payload)) {
[=15=].withMemoryRebound(to: UInt8.self, capacity: Int(plen)) {
ostream.write([=15=], maxLength: Int(plen))
}
}
if bytesWritten != (Int(plen)) {
// Could not write all bytes, report error ...
NSLog("error in Writting packet payload, not all Bytes written: bytesWritten: %d|plen: %d", bytesWritten, Int(plen))
}
您可以在 Swift 3 中将 pcap_hdr_s
转换为 Data
,反之亦然
pcap_hdr_s
->Data
var pcapHeader : pcap_hdr_s = pcap_hdr_s(magic_number ... let data = withUnsafePointer(to: &pcapHeader) { Data(bytes: UnsafePointer([=10=]), count: MemoryLayout.size(ofValue: pcapHeader)) }
Data
->pcap_hdr_s
let header: pcap_hdr_s = data.withUnsafeBytes { [=11=].pointee }
您可以将任意数据写入 InputStream
而无需创建
(NS)Data
首先是对象。 "challenge" 是如何将指针转换为
write
方法预期的指向 UInt8
指针的结构:
let ostream = OutputStream(url: url, append: false)! // Add error checking here!
ostream.open()
var pcapHeader = pcap_hdr_s(...)
let headerSize = MemoryLayout.size(ofValue: pcapHeader)
let bytesWritten = withUnsafePointer(to: &pcapHeader) {
[=10=].withMemoryRebound(to: UInt8.self, capacity: headerSize) {
ostream.write([=10=], maxLength: headerSize)
}
}
if bytesWritten != headerSize {
// Could not write all bytes, report error ...
}
以同样的方式,您可以从 InputStream
:
let istream = InputStream(url: url)! // Add error checking here!
istream.open()
let bytesRead = withUnsafeMutablePointer(to: &pcapHeader) {
[=11=].withMemoryRebound(to: UInt8.self, capacity: headerSize) {
istream.read([=11=], maxLength: headerSize)
}
}
if bytesRead != headerSize {
// Could not read all bytes, report error ...
}
如果文件可能是在不同的平台上创建的 不同的字节顺序然后你可以检查 "magic" 和交换字节 如有必要(如 https://wiki.wireshark.org/Development/LibpcapFileFormat 所述):
switch pcapHeader.magic_number {
case 0xa1b2c3d4:
break // Already in host byte order
case 0xd4c3b2a1:
pcapHeader.version_major = pcapHeader.version_major.byteSwapped
pcapHeader.version_minor = pcapHeader.version_minor.byteSwapped
// ...
default:
// Unknown magic, report error ...
}
为了简化编写和读取结构的任务,可以定义 自定义扩展方法,例如
extension OutputStream {
enum ValueWriteError: Error {
case incompleteWrite
case unknownError
}
func write<T>(value: T) throws {
var value = value
let size = MemoryLayout.size(ofValue: value)
let bytesWritten = withUnsafePointer(to: &value) {
[=13=].withMemoryRebound(to: UInt8.self, capacity: size) {
write([=13=], maxLength: size)
}
}
if bytesWritten == -1 {
throw streamError ?? ValueWriteError.unknownError
} else if bytesWritten != size {
throw ValueWriteError.incompleteWrite
}
}
}
extension InputStream {
enum ValueReadError: Error {
case incompleteRead
case unknownError
}
func read<T>(value: inout T) throws {
let size = MemoryLayout.size(ofValue: value)
let bytesRead = withUnsafeMutablePointer(to: &value) {
[=13=].withMemoryRebound(to: UInt8.self, capacity: size) {
read([=13=], maxLength: size)
}
}
if bytesRead == -1 {
throw streamError ?? ValueReadError.unknownError
} else if bytesRead != size {
throw ValueReadError.incompleteRead
}
}
}
现在您可以使用
简单地书写和阅读try ostream.write(value: pcapHeader)
try istream.read(value: &pcapHeader)
当然这只适用于像你这样的 "self-contained" 结构
pcap_hdr_s
和 pcaprec_hdr_s
.